package com.ht.WeNas.config.data;

import cn.hutool.core.io.IORuntimeException;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.StrUtil;
import com.ht.WeNas.config.WeNasCustom;
import com.ht.WeNas.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.core.io.ResourceLoader;
import org.springframework.stereotype.Component;

import javax.sql.DataSource;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * 初始化数据库
 */
@Slf4j
@Component
public class DatabaseInitializer implements CommandLineRunner {
    private final DataSource dataSource;
    private final WeNasCustom weNasCustom;
    
    public DatabaseInitializer(DataSource dataSource, WeNasCustom weNasCustom) {
        this.dataSource = dataSource;
        this.weNasCustom = weNasCustom;
    }
    
    @Autowired
    UserService userService;

    @Override
    public void run(String... args) throws Exception {
        Set<String> argSet = Arrays.stream(args).collect(Collectors.toSet());
        boolean resetDefaultUser = argSet.contains("resetDefaultUser");
        this.initDatabase(); // 先初始化
        this.createDefaultUser(resetDefaultUser);
    }

    /**
     * 创建默认用户
     * @param resetDefaultUser 是否重置默认用户
     */
    private void createDefaultUser(boolean resetDefaultUser) {
        if (resetDefaultUser) {
            createDefaultUserProcess();
        } else {
            var user = userService.getUserById(weNasCustom.getDefaultUserId());
            if (user == null) {
                createDefaultUserProcess();
            }   
        }
    }
    
    private void createDefaultUserProcess() {
        userService.insertDefaultUser();
        log.info("创建默认用户：账号:{}，密码:{}", weNasCustom.getDefaultUserName(), weNasCustom.getDefaultUserPwd());
    }

    /**
     * 初始化数据库
     * @throws Exception 过程中抛出异常
     */
    private void initDatabase() throws Exception {
        Path path = Path.of(weNasCustom.getSqlitePath());
        if (Files.exists(path)) {
            // 数据库存在，无需重复创建
            return;
        }
        log.info("本地数据库不存在，初始化数据库");
        Files.createDirectories(path.getParent());
        Files.createFile(path);
        Path readme = Path.of(path.getParent().toString(), "README.txt");
        if (!Files.exists(readme)) {
            Files.createDirectories(readme.getParent());
            Files.createFile(readme);
            Files.writeString(readme, "该文件夹为WeNas的数据存储文件夹，请不要私自改动文件夹内容，" +
                    "如果私自修改导致应用运行异常或数据丢失，后果由用户自行承担");
        }
        ClassLoader classLoader = ResourceLoader.class.getClassLoader();
        try (
                Connection conn = dataSource.getConnection();
                InputStream is = classLoader.getResourceAsStream("sql/init.sql");
        ) {
            if (is == null) {
                throw new RuntimeException("sql文件读取失败");
            }
            String sqlStr = IoUtil.read(new InputStreamReader(is, StandardCharsets.UTF_8));
            sqlStr = stripComments(sqlStr);
            String[] sqlList = sqlStr.split(";");
            for (String sql : sqlList) {
                if (StrUtil.isBlankIfStr(sql)) {
                    continue;
                }
                PreparedStatement statement = conn.prepareStatement(sql.trim());
                statement.execute();
                statement.close();
            }
        } catch (IOException e) {
            throw new IORuntimeException("数据库初始化失败，请检查文件权限", e);
        } catch (SQLException e) {
            throw new RuntimeException("数据库初始化失败", e);
        }
        log.info("数据库初始完成");
    }
    
    /**
     * 清除sql文件的注释
     * @param sql sql文件读取的字符串
     */
    private static String stripComments(String sql) {
        // Remove single-line comments
        sql = sql.replaceAll("(?m)--.*?$", "");

        // Remove multi-line comments
        Pattern pattern = Pattern.compile("/\\*[^*]*\\*+(?:[^/*][^*]*\\*+)*/", Pattern.DOTALL);
        Matcher matcher = pattern.matcher(sql);
        sql = matcher.replaceAll("");

        return sql.trim();
    }
}